package dict

import (
	"math/rand"
	"sync"
)

// SyncDict 基于sync.map实现redis数据的存储
type SyncDict struct {
	storage sync.Map
}

func MakeSyncDict() *SyncDict {
	return &SyncDict{}
}

func (s *SyncDict) Get(key string) (val interface{}, exists bool) {
	value, ok := s.storage.Load(key)
	return value, ok
}

func (s *SyncDict) Len() int {
	l := 0
	s.storage.Range(func(key, value any) bool {
		l++
		return true
	})
	return l
}

func (s *SyncDict) Put(key string, val interface{}) (result int) {
	_, exists := s.storage.Load(key)
	s.storage.Store(key, val)
	if exists {
		return 0
	}
	return 1
}

func (s *SyncDict) PutIfAbsent(key string, val interface{}) (result int) {
	_, exists := s.storage.Load(key)
	if exists {
		return 0
	}
	s.storage.Store(key, val)
	return 1
}

func (s *SyncDict) PutIfExists(key string, val interface{}) (result int) {
	_, exists := s.storage.Load(key)
	if exists {
		s.storage.Store(key, val)
		return 1
	}
	return 0
}

func (s *SyncDict) Remove(key string) (result int) {
	_, exists := s.storage.Load(key)
	s.storage.Delete(key)
	if exists {
		return 1
	}
	return 0
}

func (s *SyncDict) ForEach(consumer Consumer) {
	s.storage.Range(func(key, value any) bool {
		consumer(key.(string), value)
		return true
	})
}

func (s *SyncDict) Keys() []string {
	keys := make([]string, s.Len())
	index := 0
	s.storage.Range(func(key, value any) bool {
		keys[index] = key.(string)
		index++
		return true
	})
	return keys
}

func (s *SyncDict) RandomKeys(limit int) []string {
	l := s.Len()
	keys := make([]string, limit)
	for i := 0; i < limit; i++ {
		index := rand.Intn(l)
		i := 0
		s.storage.Range(func(key, value any) bool {
			if i == index {
				keys[index] = key.(string)
			}
			i++
			return true
		})
	}
	return keys
}

func (s *SyncDict) RandomDistinctKeys(limit int) []string {
	keys := make([]string, limit)
	index := 0
	s.storage.Range(func(key, value any) bool {
		keys[index] = key.(string)
		if index == limit {
			return false
		}
		index++
		return true
	})
	return keys
}

func (s *SyncDict) Clear() {
	*s = *MakeSyncDict()
}
